
Imports System.Threading
Imports std

Public Class distributeOperation
    Public Const defaultHoldTime As Int64 = 24000
    Public defaultSleepTimeMS As Int64 = 1

    Protected Overridable Function infocount() As Int32
        Return 0
    End Function

    'this counter will help to decide the thread count for distribuiteOperation2
    Private Shared DISTRINFO_TICKS_BETWEEN_INITIAL_AND_OPERATION As Int64

    Shared Sub New()
        DISTRINFO_TICKS_BETWEEN_INITIAL_AND_OPERATION = _
            counter.registerAverageAndLastAverage("DISTRINFO_TICKS_BETWEEN_INITIAL_AND_OPERATION", _
                                                  sampleRate:=0.01)
    End Sub

    Public Class distrInfo(Of argType, returnType)
#If (PocketPC OrElse Smartphone) Then
        Public Shared info As distrInfo(Of argType, returnType) = Nothing   'the point to this info for initialization
        Public Shared caughtInfo As Boolean = False
        Public Shared mutex As Mutex = Nothing
#End If
        Public Delegate Function createInfoDelegate() As distrInfo(Of argType, returnType)
        Protected caller As distributeOperation = Nothing
        Public done As Boolean = False  'the work on this slice has finish
        Public result As ternary = ternary.unknown 'the work result on this slice, true if the work finish without error
        Public finished As Boolean = False  'have already called finishOperation
        Private startticks As Int64 = npos   'the time when initialized

        Protected Overridable Function initialInfo(ByVal index As Int32, ByVal arg As argType) As Boolean
            Return True
        End Function

        Public Overridable Function canwork() As Boolean
            Return True
        End Function

        Public Function operation() As ternary
            counter.increase(DISTRINFO_TICKS_BETWEEN_INITIAL_AND_OPERATION, Now.Ticks() - startticks)
            Return operationImpl()
        End Function

        Protected Overridable Function operationImpl() As ternary
            Return ternary.true
        End Function

        Public Overridable Function finishOperation(ByRef rtn As returnType) As Boolean
            Return True
        End Function

        Public Function initialInfo(ByVal index As Int32, ByVal arg As argType, _
                                    ByVal inputCaller As distributeOperation) As Boolean
            startticks = Now.Ticks()
            caller = inputCaller
            Return initialInfo(index, arg)
        End Function

#If (PocketPC OrElse Smartphone) Then
        Shared Sub New()
            mutex = New Mutex()
        End Sub
#End If
    End Class

    Protected Sub distrImpl(Of t As distrInfo(Of argType, returnType), argType, returnType)(ByVal obj As Object)
        Dim info As distrInfo(Of argType, returnType) = Nothing
        info = convertor.cast(Of distrInfo(Of argType, returnType))(obj)
        Try
            If info.canwork() Then
                info.result = info.operation()
            Else
                info.result = ternary.unknown
                raiseError("info [" + GetType(t).FullName + "] cannot work when distrImpl.", _
                           errorHandle.errorType.exclamation)
            End If
        Catch ex As Exception
            raiseError("caught unexpected exception, " + ex.Message + ", call stack " + ex.StackTrace, _
                       errorHandle.errorType.critical)
            info.result = ternary.unknown
        End Try
        info.done = True
    End Sub

#If (PocketPC OrElse Smartphone) Then
    Protected Sub distrImpl(Of t As distrInfo(Of argType, returnType), argType, returnType)()
        assert(Not distrInfo(Of argType, returnType).caughtInfo, "distrInfo.caughtInfo = true before distrImpl")
        Dim info As distrInfo(Of argType, returnType) = distrInfo(Of argType, returnType).info
        distrInfo(Of argType, returnType).caughtInfo = True
        distrImpl(Of t, argType, returnType)(info)
    End Sub
#End If

    Protected Overridable Sub startInfo(Of infoType As distrInfo(Of argType, returnType), argType, returnType) _
                                       (ByVal info As infoType)
        Dim th As Thread = Nothing
        th = New Thread(AddressOf distrImpl(Of infoType, argType, returnType))
#If (PocketPC OrElse Smartphone) Then
        assert(distrInfo(Of argType, returnType).mutex.WaitOne() _
               , "cannot lock distrInfo(Of argType, returnType).mutex when distrOperation.")
        distrInfo(Of argType, returnType).caughtInfo = False
        distrInfo(Of argType, returnType).info = info
        th.Start()
        While Not distrInfo(Of argType, returnType).caughtInfo
            sleep(defaultSleepTime)
        End While
        distrInfo(Of argType, returnType).mutex.ReleaseMutex()
#Else
        th.Start(info)
#End If
    End Sub

    Private Function distrOperation(Of infoType As distrInfo(Of argType, returnType), argType, returnType) _
                                   (ByVal infos As vector(Of infoType), ByRef rtn As returnType, _
                                    Optional ByVal holdtime As Int64 = defaultHoldTime) As Boolean
        assert(Not infos Is Nothing, "infos is nothing before distrOperation.")

        If infos.size() > 0 Then
            Dim starttime As Int64 = ticksToMilliseconds(Now.Ticks)
            Dim randStart As Int32
            randStart = rnd(0, infos.size(), True)
            Dim i As Int32
            i = randStart
            Do
                infos(i).done = False
                infos(i).result = ternary.unknown
                infos(i).finished = False
                startInfo(Of infoType, argType, returnType)(infos(i))
                i += 1
                If i = infos.size() Then
                    i = 0
                End If
            Loop Until i = randStart

            i = randStart
            Do
                If infos(i).done Then
                    assert(Not infos(i).finished)
                    infos(i).finished = True
                    If infos(i).result <> ternary.unknown Then
                        If Not infos(i).finishOperation(rtn) Then
                            raiseError("finishOperation(infos(" + Convert.ToString(i) + ")) returns false." _
                                        , errorHandle.errorType.exclamation)
                        End If
                    End If
                Else
                    i -= 1
                    sleep(defaultSleepTimeMS)
                End If
                i += 1
                If i = infos.size() Then
                    i = 0
                End If
            Loop Until (i = randStart AndAlso infos(i).finished) OrElse _
                       (holdtime >= 0 AndAlso ticksToMilliseconds(Now.Ticks()) - starttime >= holdtime)

            Return (i = randStart)
        Else
            Return True
        End If
    End Function

    Protected Overridable Function createInfo _
        (Of infoType As distrInfo(Of argType, returnType), argType, returnType)() As infoType
        Return alloc(Of infoType)()
    End Function

    Protected Function distrOperation _
        (Of infoType As distrInfo(Of argType, returnType), argType, returnType) _
        (ByVal arg As argType, ByRef rtn As returnType, _
         ByVal createInfo As distrInfo(Of argType, returnType).createInfoDelegate, _
         ByVal infocount As Int32, _
         Optional ByVal holdtime As Int64 = defaultHoldTime) As Boolean
        assert(Not createInfo Is Nothing)
        Dim infos As vector(Of infoType) = Nothing
        infos = New vector(Of infoType)()
        Dim i As Int32
        For i = 0 To infocount - 1
            Dim info As infoType = Nothing
            info = createInfo()
            If Not info.initialInfo(i, arg, Me) Then
                raiseError("cannot initialize info, index = " + Convert.ToString(i), errorHandle.errorType.exclamation)
            End If
            infos.push_back(info)
        Next

        Return distrOperation(Of infoType, argType, returnType)(infos, rtn, holdtime)
    End Function

    Protected Function distrOperation _
        (Of infoType As distrInfo(Of argType, returnType), argType, returnType) _
        (ByVal arg As argType, ByRef rtn As returnType, _
         Optional ByVal holdtime As Int64 = defaultHoldTime) As Boolean
        Return distrOperation(Of infoType, argType, returnType) _
                             (arg, rtn, AddressOf createInfo(Of infoType, argType, returnType), holdtime)
    End Function

    Protected Function distrOperation _
        (Of infoType As distrInfo(Of argType, returnType), argType, returnType) _
        (ByVal arg As argType, ByRef rtn As returnType, _
         ByVal createInfo As distrInfo(Of argType, returnType).createInfoDelegate, _
         Optional ByVal holdtime As Int64 = defaultHoldTime) As Boolean
        Return distrOperation(Of infoType, argType, returnType)(arg, rtn, createInfo, infocount(), holdtime)
    End Function
End Class
